package com.sh.data.engine.domain.common.service.impl;

import com.sap.db.jdbc.HanaClob;
import com.sh.data.engine.common.enumDefinition.DSType;
import com.sh.data.engine.common.exception.BusinessException;
import com.sh.data.engine.common.util.TableNameUtil;
import com.sh.data.engine.domain.common.service.TableManager;
import com.sh.data.engine.domain.shims.db.BaseDbManager;
import com.sh.data.engine.domain.shims.db.model.FieldInfoDomain;
import com.sh.data.engine.domain.shims.sql.builder.DDLBuilder;
import com.sh.data.engine.domain.shims.sql.builder.QueryBuilder;
import com.sh.data.engine.domain.shims.sql.ddl.CreateTableParam;
import com.sh.data.engine.domain.shims.sql.select.MapRowMapper;
import com.sh.data.engine.domain.util.ClobUtil;
import com.sh.data.engine.domain.workspace.index.service.ProjectService;
import com.sh.data.engine.domain.workspace.manager.service.impl.StorageServiceImpl;
import com.sh.data.engine.repository.dao.workspace.manager.entity.StorageEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author tinglan.ys
 * @description:
 * @date 2022/4/27 上午11:47
 */
@Service
@Slf4j
public class TableManagerImpl implements TableManager {

    @Autowired
    private ProjectService projectService;

    @Autowired
    private StorageServiceImpl storageServiceImpl;

    @Override
    public String getCreateTableSql(
        BaseDbManager dbManager, List<String> fieldName, String tableName, String dbName) {
        String sql;
        DDLBuilder ddlBuilder = null;

        List<CreateTableParam.FieldInfo> fieldInfoList = new ArrayList<>();
        for (String field : fieldName) {
            CreateTableParam.FieldInfo fieldInfo = new CreateTableParam.FieldInfo();
            fieldInfo.setFieldName(field);
            fieldInfo.setFieldType(dbManager.toDbType(Types.VARCHAR));
            // 设置字段可以为空
            fieldInfo.setNullable(true);
            fieldInfoList.add(fieldInfo);
        }

        CreateTableParam createTableParam = new CreateTableParam();
        createTableParam.setSchema(dbName);
        createTableParam.setTableName(tableName);
        createTableParam.setFieldInfoList(fieldInfoList);
        createTableParam.setDbName(dbName);
        try {
            ddlBuilder = dbManager.getDDLBuilder();

            sql = ddlBuilder.create(createTableParam).toString();

        } catch (SQLException e) {
            log.error("生成建表语句异常", e);
            throw new BusinessException("生成建表语句异常:" + e.toString());
        } finally {
            if (null != ddlBuilder) {
                ddlBuilder.close();
            }
        }
        return sql;
    }

    @Override
    public List<FieldInfoDomain> getTableField(Long projectId, String tblName) {
        BaseDbManager dbManager = projectService.getDbManager(projectId);
        if (dbManager == null) {
            return null;
        }
        String schema = null;
        if (dbManager.hasSchema()) {
            // 删除表的schema
            schema = TableNameUtil.getTblSchema(tblName);
            tblName = TableNameUtil.getTblNameShort(tblName);
        }

        StorageEntity storageEntity = storageServiceImpl.getStorageInfoByProjectId(projectId);
        String storageType = storageEntity.getStorageType();
        String dbName;
        if (storageType.equals(DSType.Sap.name())) {
            // 如果是sap的话，把schema当作dbname
            dbName = storageEntity.getRmdbs().getSchema();
        } else {
            dbName = storageEntity.getRmdbs().getDbName();
        }
        if (storageType.equalsIgnoreCase(DSType.DM.name())) {
            if (tblName.contains(".")) {
                String[] splitDM = tblName.split("\\.", 2);
                tblName = splitDM[1];
            }
        }

        if (StringUtils.isEmpty(dbName)) {
            throw new BusinessException("dbName为空");
        }
        try {
            List<FieldInfoDomain> fieldList;
            if (StringUtils.isNotBlank(schema)) {
                fieldList = dbManager.getFieldList(dbName, schema, tblName);
            } else {
                fieldList = dbManager.getFieldList(dbName, tblName);
            }
            return fieldList;
        } catch (SQLException throwable) {
            throwable.printStackTrace();
        } finally {
            dbManager.close();
        }
        return null;
    }

    @Override
    public List<Map<String, Object>> getDataBySql(String targetTblName, Long projectId, String sql) {
        // 查询数据
        final BaseDbManager dbManager = projectService.getDbManager(projectId);
        final StorageEntity storageEntity = storageServiceImpl.getStorageInfoByProjectId(projectId);
        String storageType = storageEntity.getStorageType();

        List<Map<String, Object>> datas;

        QueryBuilder queryBuilder = null;
        try {
            if (storageType.equals(DSType.Sap.name())) {
                // 如果存储是Sap
                queryBuilder = dbManager.getQueryBuilder();
                datas = queryBuilder.selectSql(sql).list(new MapRowMapper());
                // 要把hanaClob转化为String
                for (Map<String, Object> data : datas) {
                    Set<String> keySet = data.keySet();
                    for (String key : keySet) {
                        Object value = data.get(key);
                        if (value instanceof HanaClob) {
                            data.put(key, ClobUtil.hanaClobToString2((HanaClob) value));
                        }
                    }
                }
            } else {
                // 如果存储是其他
                queryBuilder = dbManager.getQueryBuilder();
                datas = queryBuilder.selectSql(sql).list(new MapRowMapper());
            }

        } catch (SQLException throwable) {
            log.error("查询数据异常", throwable);
            throw new BusinessException("查询数据异常:" + throwable.toString());
        } finally {
            if (null != queryBuilder) {
                queryBuilder.close();
            }
        }
        return datas;
    }

    @Override
    public List<Map<String, Object>> getDataLimit10(String targetTblName, Long projectId) {

        // 查询数据
        final BaseDbManager dbManager = projectService.getDbManager(projectId);
        final StorageEntity storageEntity = storageServiceImpl.getStorageInfoByProjectId(projectId);
        // schema 取表名中带过来的schema 而非底座配置的schema 这个要注意
        String schema = TableNameUtil.getTblSchema(targetTblName);
        String tblNameShort = TableNameUtil.getTblNameShort(targetTblName);
        String storageType = storageEntity.getStorageType();

        List<Map<String, Object>> datas;

        QueryBuilder queryBuilder = null;
        try {
            String sql;
            if (storageType.equals(DSType.Sap.name())) {
                sql = "select * from \"" + schema + "\".\"" + tblNameShort + "\" limit 10";
                queryBuilder = dbManager.getQueryBuilder();
                datas = queryBuilder.selectSql(sql).list(new MapRowMapper());
                // 要把hanaClob转化为String
                for (Map<String, Object> data : datas) {
                    Set<String> keySet = data.keySet();
                    for (String key : keySet) {
                        Object value = data.get(key);
                        if (value instanceof HanaClob) {
                            data.put(key, ClobUtil.hanaClobToString2((HanaClob) value));
                        }
                    }
                }
            } else if (storageType.equals(DSType.PostgreSQL.name())
                || storageType.equals(DSType.MatrixDB.name())) {
                // 如果存储是pg 要拼接上schema
                sql = "select * from \"" + schema + "\".\"" + tblNameShort + "\" limit 10";
                queryBuilder = dbManager.getQueryBuilder();
                datas = queryBuilder.selectSql(sql).list(new MapRowMapper());
            } else if (storageType.equals(DSType.KINGBASE8.name())) {
                sql = "select * from \"" + schema + "\".\"" + tblNameShort + "\" limit 10";
                queryBuilder = dbManager.getQueryBuilder();
                datas = queryBuilder.selectSql(sql).list(new MapRowMapper());
            } else if (storageType.equals(DSType.DM.name())) {
                if (StringUtils.isEmpty(schema)) {
                    schema = storageEntity.getRmdbs().getDbName();
                }
                // 如果存储是其他 表名不要加引号 无论是双引号还是单引号 tidb hive
                sql = "select * from \"" + schema + "\".\"" + tblNameShort
                    + "\"  limit 10";
                queryBuilder = dbManager.getQueryBuilder();
                datas = queryBuilder.selectSql(sql).list(new MapRowMapper());
            } else {
                // 如果存储是其他 表名不要加引号 无论是双引号还是单引号 tidb hive
                sql = "select * from " + targetTblName + " limit 10";
                queryBuilder = dbManager.getQueryBuilder();
                datas = queryBuilder.selectSql(sql).list(new MapRowMapper());
            }
        } catch (SQLException throwable) {
            log.error("查询数据异常", throwable);
            throw new BusinessException("查询数据异常:" + throwable.toString());
        } finally {
            if (null != queryBuilder) {
                queryBuilder.close();
            }
        }
        return datas;
    }

    @Override
    public List<Map<String, Object>> getDataBySqlLimit10(Long projectId, String sql) {
        // 查询数据
        final BaseDbManager dbManager = projectService.getDbManager(projectId);
        final StorageEntity storageEntity = storageServiceImpl.getStorageInfoByProjectId(projectId);
        String storageType = storageEntity.getStorageType();

        List<Map<String, Object>> datas;

        QueryBuilder queryBuilder = null;
        try {
            if (storageType.equals(DSType.Sap.name())) {
                // 如果存储是Sap
                queryBuilder = dbManager.getQueryBuilder();
                datas = queryBuilder.selectSql(sql).list(new MapRowMapper());
                // 要把hanaClob转化为String
                for (Map<String, Object> data : datas) {
                    Set<String> keySet = data.keySet();
                    for (String key : keySet) {
                        Object value = data.get(key);
                        if (value instanceof HanaClob) {
                            data.put(key, ClobUtil.hanaClobToString2((HanaClob) value));
                        }
                    }
                }
            } else {
                // 如果存储是其他
                queryBuilder = dbManager.getQueryBuilder();
                datas = queryBuilder.selectSql(sql).limit(0, 10).list(new MapRowMapper());
            }

        } catch (SQLException throwable) {
            log.error("查询数据异常", throwable);
            throw new BusinessException("查询数据异常:" + throwable.toString());
        } finally {
            if (null != queryBuilder) {
                queryBuilder.close();
            }
        }
        return datas;
    }
}
